篇首语:本文由编程笔记#小编为大家整理,主要介绍了Python入门自学进阶-Web框架——14Django的Form验证相关的知识,希望对你有一定的参考价值。
Django的Form验证
用户名称: 用户邮箱: 用户邮箱:html>
% csrf_token %
def logintest(req):
if req.method == "GET":
return render(req,'logintest.html')
elif req.method == "POST":
u = req.POST.get("username")
e = req.POST.get("email")
p = req.POST.get("pwd")
print("对获取的数据进行处理:1,校验;2,数据库操作",u,e,p)
return render(req,'logintest.html',)
存在的几个问题:
1、对用户提交的数据进行验证,要求提示信息准确,即哪个字段的输入不符合要求,在哪个字段进行提示错误信息;
2、如果提交的数据项比较多,后台req.POST.get()会大量出现;
3、如果要进行数据库操作,如使用filter()或create(),参数中要写大量如username=,email=,pwd=。。。等长的参数;
4、对于前端,如果数据项验证失败,即通过form提交了表单,此时前端的所有数据都清空了,而我们期望正确的输入框数据还在(当然,ajax提交不涉及这个问题,ajax提交后数据依然存在);
用户提交数据的验证:
长度、类型、格式验证,重用性要高。
验证分为前端后后端
后端,使用一个模板:
- 邮箱格式
- 用户,名称长度>4
- 密码,长度>7
Django提供了Form验证类模板:
# 定义模板
from django import forms
class LoginForm(forms.Form):
# 模板中的元素
username = forms.CharField(min_length=4)
email = forms.EmailField()
使用验证类进行验证:
def logintest(req):
if req.method == "GET":
return render(req,'logintest.html')
elif req.method == "POST":
obj = LoginForm(req.POST)
# 验证
status = obj.is_valid()
value_right = obj.clean()
print('value_right:',value_right)
value_error = obj.errors
print('value_error:',value_error)
print('status:',status)
if obj.is_valid():
value_right = obj.clean()
# create(**value_right) 数据库增加记录,参数直接使用**value_right
else:
value_error = obj.errors.as_json()
print('value_error_asjson:',value_error)
return render(req,'logintest.html',)
先定义一个模板,这个模板要继承自django的forms中的Form类,然后定义元素,注意,这里的变量名,如username、email不是随意取的,必须与前台form表单中各提交数据标签的name值一致,然后就是具有特定验证功能的CharField()、EmailField()等。在视图函数中使用这个模板
进行验证,先实例化一个模板对象,将req.POST作为参数,这样就会自动获取POST中的对应值进行验证。生成对象并不能验证,还需要调用is_valid()方法,这时才会进行验证,结果为True或False,验证无措,才会返回True,只要有一个字段验证错误,就是False。clean()方法是获取验证正确的字段的一个字典,errors则是错误字段及错误信息的一个无序列表字符串,使用as_json()转换为json字符串。
因为email字段输入的不符合emailed格式,验证错误,value_error,即errors显示email的错误列表信息,转换为json字符串显示格式,is_valid()结果为false。clean()只是正确字段的字典。
这里有一个问题,就是如果模板中没有定义的字段,在clean()中不能获取,如这里的pwd字段,还需要使用POST.get()获取。
通过错误信息的json格式,可以看到错误的种类,即code的值,这里有invalid——格式不符合,min_length——最小长度不够,required——字段需要值,即字段为空了等。相应的message就是对应错误代码的说明信息,可以是汉字说明。
# 定义模板
from django import forms
class LoginForm(forms.Form):
# 模板中的元素
username = forms.CharField(min_length=4,error_messages="min_length":"用户名长度不能小于4","required":"用户名不能为空")
email = forms.EmailField(error_messages="invalid":"邮箱名格式不符合要求","required":"邮箱不能为空")
运行打印结果:
value_right:
value_error:
转换为json时,汉字转换为Unicode编码了。
对于errors属性,通过打印结果看,好像是一个字符串,实际是什么呢?通过type(obj.errors),打印出类型:
@html_safe
class ErrorDict(dict):
"""
A collection of errors that knows how to display itself in various formats.
The dictionary keys are the field names, and the values are the errors.
"""
def as_data(self):
return f: e.as_data() for f, e in self.items()
def get_json_data(self, escape_html=False):
return f: e.get_json_data(escape_html) for f, e in self.items()
def as_json(self, escape_html=False):
return json.dumps(self.get_json_data(escape_html))
def as_ul(self):
if not self:
return ''
return format_html(
'',
format_html_join('', '', self.items())
)
def as_text(self):
output = []
for field, errors in self.items():
output.append('* %s' % field)
output.append('\\n'.join(' * %s' % e for e in errors))
return '\\n'.join(output)
def __str__(self):
return self.as_ul()
继承自字典dict,我们看到了as_json(),返回的是json.dumps(),即转换为json格式字符串。而其__str__()是返回as_ul(),看as_ul(),其格式就是我们看到的打印的结果。
因为errors是一个
print(obj.errors['email'])结果为:
,这是不是一个字符串呢?打印类型print(type(obj.errors['email'])),结果为:
也就是说,在生成obj对象时,相关的错误信息就存在对象中了,可以将此对象传递给前端:
def logintest(req):
if req.method == "GET":
return render(req,'logintest.html')
elif req.method == "POST":
obj = LoginForm(req.POST)
# 验证
status = obj.is_valid()
value_right = obj.clean()
print('value_right:',value_right)
value_error = obj.errors
print('value_error:',value_error['email'][0])
print('status:',status)
if obj.is_valid():
value_right = obj.clean()
# create(**value_right) 数据库增加记录,参数直接使用**value_right
else:
value_error = obj.errors.as_json()
print('value_error_asjson:',value_error)
return render(req,'logintest.html','oo':obj)
用户名称: oo.errors.username.0 用户邮箱: oo.errors.email.0 用户邮箱:
前端只需显示一个错误信息,所以只取索引0的值。对于第一个get请求,没有传递oo对象,对于django来说,没有的对象,返回的就是null,但对于其他语言,有可能出错。
现在的还有个问题是,form提交后,如果有字段出错,希望字段还保留输入的信息,要实现这个功能,就不能我们自己写input标签,需要Form来实现。
obj = LoginForm()
print(obj['username'])
print(obj['email'])
结果为:
对于不传参数的对象,obj['username']是生成一个input标签。
传递一个参数:obj=LoginForm('username':'qwert','email':'qw@123),则结果为
在前端,可以使用这种方式自动生成input标签:
用户名称: oo.username oo.errors.username.0 用户邮箱: oo.email oo.errors.email.0 用户邮箱:
% csrf_token %
def logintest(req):
if req.method == "GET":
obj = LoginForm()
return render(req,'logintest.html','oo':obj)
elif req.method == "POST":
obj = LoginForm(req.POST)
if obj.is_valid():
value_right = obj.clean()
# create(**value_right) 数据库增加记录,参数直接使用**value_right
else:
return render(req,'logintest.html','oo':obj)
这样就能在输入错误后保留原数据。
需要先运行is_valid()然后才能clean()
ajax实现提交验证,保留原输入值无需实现,ajax本身不刷新页面,输入值一直保持
用户名称: 用户邮箱:
用户密码:
前端:获取表单的数据,可以使用serialize()函数,这个获取到的数据可以直接作为ajax的data值使用。
def loginajax(req):
if req.method == "GET":
return render(req,'loginajax.html')
elif req.method == "POST":
ret = 'status':True,'error':None,'data':None
obj = LoginForm(req.POST)
if obj.is_valid():
print(obj.clean())
print(req.POST.get('pwd'))
else:
res_str = obj.errors.as_json()
ret['status'] = False
ret['error'] = res_str
return HttpResponse(json.dumps(ret))
后端ajax提交需要直接HttpResponse返回一个json格式的字符串,使用了dumps()方法。
上面的实现方式,对于前端,在错误信息处理上,进行了两次JSON.parse(),有些繁琐。
对后端返回的错误信息进行处理:
def loginajax(req):
if req.method == "GET":
return render(req,'loginajax.html')
elif req.method == "POST":
ret = 'status':True,'error':None,'data':None
obj = LoginForm(req.POST)
if obj.is_valid():
print(obj.clean())
print(req.POST.get('pwd'))
else:
# res_str = obj.errors.as_json()
# ret['status'] = False
# ret['error'] = res_str
ret['status'] = False
ret['error'] = obj.errors.as_data()
# obj.errors.as_data()的值为:'username': [ValidationError(['用户名不能为空'])], 'email': [ValidationError(['邮箱名格式不符合要求'])]
# 其value中是如下类的实例:django.core.exceptions.ValidationError
# 将其进行一次反序列化,即将ValidationError(['用户名不能为空'])进行一次反序列化
# 最后将ret反序列化,这样一共进行了两次反序列化
# ValidationError(['用户名不能为空'])进行一次反序列化,因为其在ret中,所以可以在反序列化ret时,使用cls=参数,指定一个进行反序列化的类
return HttpResponse(json.dumps(ret,cls=JsonCustomEncode))
from django.core.validators import ValidationError
class JsonCustomEncode(json.JSONEncoder):
def default(self, field):
if isinstance(field,ValidationError):
return 'code':field.code,'message':field.message
else:
return json.JSONEncoder.default(self,field)
前端
用户名称: 用户邮箱:
用户密码:
以上是Form验证的基本用法,日常开发中需要的其他一些问题:
- 除了字符验证和邮件验证,还有哪些验证,可不可以自己定制规则
- 除了生成input标签,是否可以生成其他标签
- 显示默认值